package portal.initial;


import java.util.List;
import java.util.concurrent.Semaphore;

import javax.servlet.ServletContext;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.web.context.ServletContextAware;

import beans.HttpConfig;
import beans.HttpResult;
import beans.RunningTask;
import dao.TaskDao;
import engine.BIEngine0_1.TaskThread;
import portal.beans.Gpu;
import portal.beans.Node;
import portal.common.MyStringUtils;
import portal.common.ShellExec;
import portal.conf.ElimGPU;
import portal.conf.EtcHostsConf;
import portal.conf.entity.BaseConf;
import portal.conf.entity.EtcHostsEntity;
import portal.conf.entity.GPUEntity;
import portal.dao.ScheduleGpuDetailDao;
import portal.dao.ScheduleJobDetailDao;
import portal.dao.ScheduleSocketLogDao;
import portal.engine.JobOperator;
import portal.engine.UpdateJobThread;
import portal.mybatis.dao.service.HostService;
import utils.Log4jInit;

@Component
@Scope("singleton")
@Lazy(false)
public class DataInit implements ServletContextAware {
	private static UpdateJobThread updateJobThread;
    /**
     * 信号量，预留为后续Action中调用防止重复调用。
     * **/
    private static Semaphore seHosts=new Semaphore(1);
    private static Semaphore seGpu=new Semaphore(1);
    //private static ServletContext servletContext;
    //@Autowired
    private static ScheduleGpuDetailDao scheduleGpuDetailDao;
    //@Autowired
    private static HostService hostService;
    //@Autowired
    private static EtcHostsConf etcHostsConf;
    //@Autowired
    private static ElimGPU elimGpu ;
    private static ScheduleJobDetailDao scheduleJobDetailDao;
    //@Autowired
    private static ScheduleSocketLogDao scheduleSocketLogDao;
    @Override
    public void setServletContext(ServletContext servletContext) {
        //DataInit.servletContext = servletContext;
//        loadHosts();
//        checkGpu();
//        initJob();
    }
    @Autowired
    public void setHostService(HostService h){
        hostService=h;
    }
    @Autowired
    public void setEtcHostsConf(EtcHostsConf e){
        etcHostsConf=e;
    }
    @Autowired
    public void setScheduleGpuDetailDao(ScheduleGpuDetailDao dao){
        scheduleGpuDetailDao=dao;
    }
    @Autowired
    public void setElimGpu(ElimGPU e){
    	elimGpu=e;
    }
    /****
     * 静态方法，类加载时直接调用，读取现有的elim.gpu中的信息，并与数据库中进行同步，
     * ****/
    private static void checkGpu(){
        if(seGpu.tryAcquire()==false)
            return;
        try{
            //loadContext();
            Log4jInit.logger.info("-------------------GPU Checking----------------------------");
            
            List<BaseConf> list= elimGpu.selectAllConf();
            if(list==null)
            	return;
            //Log4jInit.logger.info("list.size = "+list.size());
            int i = 0;
            for(BaseConf bConf :list){
                Gpu g=scheduleGpuDetailDao.getGpuByVersion(bConf.getKey());
                if(null==g ||g.getGpuVersion()==null){
                    GPUEntity gpu= (GPUEntity)bConf;
                    Gpu gpu1= new Gpu();
                    gpu1.setGpuIdentify(gpu.getRes());
                    gpu1.setGpuVersion(gpu.getName());
                    gpu1.setGpuDetail(gpu.getInfo());
                    boolean addFlag = scheduleGpuDetailDao.addGpu(gpu1);
                    if(addFlag==false)
                        Log4jInit.logger.info(gpu +" 写入数据库失败");
                    else i++;
                }else{
	                    //Log4jInit.logger.info(g.getGpuDetail()+" "+g.getGpuIdentify() +" "+g.getGpuVersion());
	                }
            }
            Log4jInit.logger.info("-----------------数据库新增 "+i+" 条记录---------------------------");
            Log4jInit.logger.info("-------------------GPU Checked----------------------------");
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            seGpu.release();
        }
    }
    /***
     * 加载Host 信息，维护数据库与系统的一致性（非实时，仅仅保证启动时一致性）
     * 分两种情况，获取的jhosts命令执行后的结果hostName是否存在
     * 1、不存在时：需要新增记录，
     *     1.1 先从 etc/hosts 下获取IP
     *     1.2 从 jgroups 中获取groupName
     *     1.3 将GroupName ,HostName ,HostIP,及GPU 信息插入到数据库。
     * 2、存在时：
     * 	   2.1 检查该结点的IP 是否匹配
     * 	   2.2 检查该结点GroupName是否匹配
     *	   2.3 检查该节点的GPU 是否匹配
     * **/
    private  static void loadHosts(){
        if(seHosts.tryAcquire()==false)
            return;
        try{
            //loadContext();
            Log4jInit.logger.info("-------------------Host Checking----------------------------");
            String hostDetail= ShellExec.command("jhosts");
            if(hostDetail==null ||!hostDetail.contains("HOST_NAME")){
            	Log4jInit.logger.info("-------------------loading hosts failed ,checking is skipped----------------------------");
            	return;
            	}
            String hostGroups=ShellExec.command("jhostgroup");
            if(hostGroups==null || !hostGroups.contains("GROUP_NAME")){
            	Log4jInit.logger.info("-------------------loading host Groups failed ,checking is skipped----------------------------");
            	return;
            	}
            String[] arr=hostDetail.split("\n");
            //String arr2[arr.length][] ;
            //执行节点无效操作，将数据库中所有节点置为无效
            hostService.updateAllNodeToInactive();
            for(String s:arr){
                if(s==arr[0]){//第一行未标题忽略
                    Log4jInit.logger.info("第一行标题忽略");
                    continue;
                }
                String[] nodeA= MyStringUtils.strictSpace(s).split(" ");
                if(nodeA==null||nodeA.length==0){
                    Log4jInit.logger.info("----------------------------------Analysis Node Failed---------------------------------------------");
                    continue;
                }
                EtcHostsEntity e=(EtcHostsEntity)etcHostsConf.findConfByName(nodeA[0]);//根据nodeName获取etc/hosts 中详细，此处关注IP
                if(e==null){//未找到，则无法确认该节点的ip
                    //Log4jInit.logger.info("节点不存在，无法找到其对应IP");
                    Log4jInit.logger.info("-----------------------CAN NOT Get The IP Of Node Named 【"+nodeA[0]+"】--------------------");
                    continue;
                }
                Node node=hostService.selectByName(nodeA[0]);
                String gpuKey=null;
                if(nodeA.length>9)
                    gpuKey=nodeA[9];
                if(node==null){//未找到，需要将该节点名，group,GPU 及IP 填入数据库
                    hostService.insertNode(nodeA[0], findGroupNameByHost(hostGroups.split("\n"),nodeA[0]), e.getIp(), gpuKey,nodeA[1]);

                }else{//节点存在则暂不操作，正常应该根据节点名校验其 Gpu 信息
                    //获取视图中，对应信息GPU 信息，进行比较，若一致，则不做调整，
                    //若不一致，则查找该GPU 信息对应的ID ，并将ID 更新到对应的子段。
                    //最便捷的实现方式，根据已知的节点ID 直接更新不再查找是否存在。
               hostService.updateNodeById(node.getNodeId(), findGroupNameByHost(hostGroups.split("\n"),nodeA[0]), e.getIp(), gpuKey,nodeA[1]);
                }
                //Log4jInit.logger.info("line:  "+node.length );
            }
            Log4jInit.logger.info("-------------------Host Checked----------------------------");
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            seHosts.release();
        }
    }
    private static String findGroupNameByHost(String[] group,String host){
        String ret="";
        if(group==null ||group.length==0 || host==null ||host.length()==0)
            return null;
        for(String s:group){
            if(s==group[0])//跳过第一标题
                continue;
            String[] g= MyStringUtils.strictSpace(s).split(" ");
            for(String h:g){
                if(h==g[0])//不比较groupName
                    continue;
                //Log4jInit.logger.info("g:"+g[0]);
                if(h.equals(host)){//在s group 下查找该结点是否存在
                    if(ret.length()>0)
                        ret +=" ,";
                    ret +=g[0];//将当前的groupName记录下来，
                    break;
                }
            }
        }
        return ret;
    }
    public static void initJob(){
    	//启动作业更新线程，定时更新调度作业详情
        if (updateJobThread == null) {
            updateJobThread = new UpdateJobThread(scheduleSocketLogDao,scheduleJobDetailDao);
            updateJobThread.start(); // servlet 上下文初始化时启动 socket
        }

        //将因tomcat关闭而序列化到数据库中的任务，添加到任务线程池中
        boolean isSuccess = DBToRunningTask();
    }
    private static boolean DBToRunningTask(){
        /**
         * 从服务器获取token
         */
        HttpResult tokenResult = JobOperator.getToken(HttpConfig.userName, HttpConfig.passWord);
        if(tokenResult==null)
        	return false;
        boolean isSuccess = true;
        if (tokenResult.isResult()) {
            String token = tokenResult.getMessage();
            List<Object> taskThreads = new TaskDao().getDisconnectTaskThread();
            //将任务全部放入线程池
            for (Object one : taskThreads) {
                TaskThread task = (TaskThread) one;
                RunningTask.TASKMAP.setTask(task.runningTaskBean.getTaskHash(), task);
                Log4jInit.logger.info("重启任务id"+task.runningTaskBean.getTaskHash());
                //将一些因tomcat断开而调用JobCallBack失败的任务重新执行
                isSuccess = isSuccess & task.connectTask(token);
            }
        }else {
             isSuccess = false;
        }
        return isSuccess;
    }
//	public static ScheduleJobDetailDao getScheduleJobDetailDao() {
//		return scheduleJobDetailDao;
//	}
//	public static ScheduleSocketLogDao getScheduleSocketLogDao() {
//		return scheduleSocketLogDao;
//	}
    @Autowired
	public  void setScheduleJobDetailDao(ScheduleJobDetailDao scheduleJobDetailDao) {
		DataInit.scheduleJobDetailDao = scheduleJobDetailDao;
	}
    @Autowired
	public  void setScheduleSocketLogDao(ScheduleSocketLogDao scheduleSocketLogDao) {
		DataInit.scheduleSocketLogDao = scheduleSocketLogDao;
	}
    
}
